#include "ShapeStyleDef.h"
#include "Stream.h"

namespace LightPlayer{

	FILLSTYLE::FILLSTYLE(){
		init();
	}

	FILLSTYLE::FILLSTYLE( RGBA _Color ){
		init();
		m_FillStyleType = eSolidFill;
		m_Color = _Color;
	}

	void FILLSTYLE::init(){
		m_FillStyleType = eSolidFill;
		m_Color = RGBA();
		m_GradientMatrix.setIdentity();
		m_Gradient.init();
		m_FocalGradient.init();
		m_BitmapId = 0;
		m_BitmapMatrix.setIdentity();
		m_pBitmap = NULL;
	}

	void FILLSTYLE::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/){
		init();
		m_FillStyleType = stream->read_u8();

		if(				m_FillStyleType == eSolidFill )
		{
			if(tag_shape == eDefineShape || tag_shape == eDefineShape2 ){
				m_Color.readRGBFromStream(stream);
			} else {
				m_Color.readFromStream(stream);
			}
		} 
		else if(		m_FillStyleType == eLinearGradientFill ||
						m_FillStyleType == eRadialGradientFill ||
						m_FillStyleType == eFocalRadialGradientFill ) 
		{
			m_GradientMatrix.readFromStream(stream);
			// Unlike all other MATRIX in Swf format, Gradient matrix are store in TWIPS (don't ask me why -_-)
			// A scale of (20,20) is 1 pixel-per-unit.
			m_GradientMatrix._11 *= 0.05f;
			m_GradientMatrix._12 *= 0.05f;
			m_GradientMatrix._21 *= 0.05f;
			m_GradientMatrix._22 *= 0.05f;

			if( m_FillStyleType == eLinearGradientFill ||
				m_FillStyleType == eRadialGradientFill ){
				m_Gradient.readFromStream(stream);
				m_Gradient.m_isLinear = m_FillStyleType == eLinearGradientFill;
			} else {
				m_FocalGradient.readFromStream(stream);
			}
		} 
		else if(		m_FillStyleType == eRepeatingBitmapFill ||
						m_FillStyleType == eClippedBitmapFill ||
						m_FillStyleType == eNonSmoothedRepeatingBitmapFill ||
						m_FillStyleType == eNonSmoothedClippedBitmapFill   ) 
		{
			m_BitmapId = stream->read_u16();
			m_BitmapMatrix.readFromStream(stream);
			// Unlike all other MATRIX in swf format, Bitmap matrix are store in TWIPS (don't ask me why -_-)
			// A scale of (20,20) is 1 pixel-per-unit.
			m_BitmapMatrix._11 *= 0.05f;
			m_BitmapMatrix._12 *= 0.05f;
			m_BitmapMatrix._21 *= 0.05f;
			m_BitmapMatrix._22 *= 0.05f;
		}
	}

	LightPlayer::FILLSTYLE FILLSTYLEARRAY::s_empty_fill_style;
	LightPlayer::FILLSTYLE FILLSTYLEARRAY::s_white_fill_style( RGBA(255,255,255,255) );


	FILLSTYLEARRAY::FILLSTYLEARRAY(){
		init();
	}

	void FILLSTYLEARRAY::init(){
		m_FillStyles.clear();
	}


	FILLSTYLE& FILLSTYLEARRAY::at( uint32 pos ){
		if( pos == 0 || pos > m_FillStyles.size() ){
			return s_empty_fill_style;
		}
		else{
			return m_FillStyles[ pos - 1 ];
		}
	}


	void FILLSTYLEARRAY::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/ ){
		init();
		addFromStream( stream, tag_shape );
	}

	void FILLSTYLEARRAY::addFromStream( Stream* stream, int tag_shape /*= eDefineShape*/ ){
		int FillStyleCount = stream->read_u8();
		if( FillStyleCount == 0xFF && 
			(tag_shape == eDefineShape2 || tag_shape == eDefineShape3) ){
				FillStyleCount = stream->read_u16();
		}
		int prev_size = m_FillStyles.size(); 
		m_FillStyles.resize( prev_size + FillStyleCount );
		for (int32 i=0; i<FillStyleCount; i++){
			m_FillStyles[ prev_size + i ].readFromStream(stream,tag_shape);
		}
	}

	LINESTYLE::LINESTYLE(){
		init();
	}

	void LINESTYLE::init(){
		m_Width = 1.0f;
		m_Color = RGBA();
	}

	void LINESTYLE::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/ ){
		init();
		m_Width = TWIPS_TO_PIXELS( stream->read_u16() );
		if(tag_shape == eDefineShape || tag_shape == eDefineShape2 ){
			m_Color.readRGBFromStream(stream);
		} else {
			m_Color.readFromStream(stream);
		}
	}


	LINESTYLE2::LINESTYLE2(){
		init();
	}

	void LINESTYLE2::init(){
		m_Width = 1.0f;
		m_StartCapStyle = eRoundCap;
		m_EndCapStyle = eRoundCap;
		m_JoinStyle = eRoundJoin;
		m_NoHScaleFlag = false;
		m_NoVScaleFlag = false;
		m_PixelHintingFlag = false;
		m_Close = true;
		m_MiterLimitFactor = 1.0f;
		m_Color = RGBA();
		m_FillStyle.init();
	}

	void LINESTYLE2::readStyle1FromStream( Stream* stream, int tag_shape /*= eDefineShape*/ ){
		init();
		m_Width = TWIPS_TO_PIXELS( stream->read_u16() );
		if(tag_shape == eDefineShape || tag_shape == eDefineShape2 ){
			m_Color.readRGBFromStream(stream);
		} else {
			m_Color.readFromStream(stream);
		}
	}

	void LINESTYLE2::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/ )	{
		init();
		m_Width = TWIPS_TO_PIXELS( stream->read_u16() );
		m_StartCapStyle = stream->read_uint(2);
		m_JoinStyle = stream->read_uint(2);

		bool has_fill_flag = stream->read_bool();

		m_NoHScaleFlag = stream->read_bool();
		m_NoVScaleFlag = stream->read_bool();
		m_PixelHintingFlag = stream->read_bool();

		uint8 skipped = stream->read_uint(5);

		m_Close = ! stream->read_bool();
		if( m_JoinStyle == eMiterJoin ){
			m_MiterLimitFactor = stream->read_fixed16();
		}
		if(has_fill_flag){
			m_FillStyle.readFromStream(stream, tag_shape);
		} else {
			m_Color.readFromStream(stream);
		}
	}


	LightPlayer::LINESTYLE2 LINESTYLEARRAY::s_empty_line_style;

	LINESTYLEARRAY::LINESTYLEARRAY(){
		init();
	}

	void LINESTYLEARRAY::init(){
		m_LineStyles2.clear();
	}

	void LINESTYLEARRAY::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/ ){
		init();
		addFromStream(stream,tag_shape);
	}

	void LINESTYLEARRAY::addFromStream( Stream* stream, int tag_shape /*= eDefineShape*/ ){
		int LineStyleCount = stream->read_u8();
		if( LineStyleCount == 0xFF ){
			LineStyleCount = stream->read_u16();
		}
		
		int prev_size = m_LineStyles2.size();
		m_LineStyles2.resize( prev_size + LineStyleCount );
			
		for (int32 i=0; i<LineStyleCount; i++){
			if( tag_shape != eDefineShape4 ){
				m_LineStyles2[ prev_size + i ].readStyle1FromStream(stream,tag_shape);
			}
			else{
				m_LineStyles2[ prev_size + i ].readFromStream(stream,tag_shape);
			}
		}
	}

	LINESTYLE2& LINESTYLEARRAY::at( uint32 pos ){
		if( pos == 0 ){
			return s_empty_line_style;
		}
		else{
			return m_LineStyles2[ pos - 1 ];
		}
	}

	


	GRADRECORD::GRADRECORD(){
		init();
	}

	void GRADRECORD::init(){
		m_Ratio = 0;
		m_Color = RGBA();
	}

	void GRADRECORD::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/ ){
		init();
		m_Ratio = stream->read_u8();
		if(tag_shape == eDefineShape || tag_shape == eDefineShape2 ){
			m_Color.readRGBFromStream(stream);
		} else {
			m_Color.readFromStream(stream);
		}
	}


	GRADIENT::GRADIENT(){
		init();
	}

	void GRADIENT::init(){
		m_isLinear = true;
		m_SpreadMode = ePadMode;
		m_InterpolationMode = eNormalRGBInterpolation;
		m_GradientsRecords.clear();

		memset(m_ColorControl,0,GRADIENT_COLOR_CONTROLE_SIZE*sizeof(float));
		for (int i=0; i<GRADIENT_MAX_CONTROL; i++){
			m_RatioControl[i] = 100000.0f;
		}
	}

	void GRADIENT::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/ ){
		init();
		stream->align();
		m_SpreadMode = stream->read_uint(2);
		m_InterpolationMode = stream->read_uint(2);
		int gradient_number = stream->read_uint(4);
		m_GradientsRecords.resize(gradient_number);
		for (int i=0; i<gradient_number; i++){
			m_GradientsRecords[i].readFromStream(stream,tag_shape);
		}

		computeControlBuffer();
	}

	void GRADIENT::computeControlBuffer(){
		int gradient_number = m_GradientsRecords.size();
		assert(gradient_number <= 8 );
		for (int i=0; i<gradient_number; i++){
			if(i>0){
				assert( m_GradientsRecords[i].m_Ratio >= m_GradientsRecords[i-1].m_Ratio );
			}
			m_RatioControl[i] = m_GradientsRecords[i].m_Ratio / 255.0f;
			m_ColorControl[i*4 + 0] = m_GradientsRecords[i].m_Color.R01();
			m_ColorControl[i*4 + 1] = m_GradientsRecords[i].m_Color.G01();
			m_ColorControl[i*4 + 2] = m_GradientsRecords[i].m_Color.B01();
			m_ColorControl[i*4 + 3] = m_GradientsRecords[i].m_Color.A01();
		}
	}


	FOCALGRADIENT::FOCALGRADIENT()	{
		init();
	}

	void FOCALGRADIENT::init(){
		m_Gradient.init();
		m_FocalPoint = 0.0f;
	}

	void FOCALGRADIENT::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/ ){
		init();
		m_Gradient.readFromStream(stream);
		assert(0);
		// To check : I'm not sure read_fixed16() is correct, is the swf PDF this field is discribe
		// as FIXED8, but type doesn't exist, I think they meant FIXED8.8 (as they did before in the pdf)
		// and so Fixed16, But I'm not sure.  
		// the assert is here to remember me to check the first time I will try to read this tag in my test
		// it could be remove just after be sure is the correct thing to read.
		
		// If you read this comment, it's means that I never encounter that tag during my test (and is possible
		// as FOCALGRADIENT is not so much use), so I don't assume the behavior introduce by this read function
		// please test it for me :)
		m_FocalPoint = stream->read_fixed16();
	}

};